/** \file chatgpt.c 
 *  \brief chatgpt
 */
#include <assert.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <signal.h>
#include <string>

//#include "speechnls.h" 

#include "het_ringbuf.h" 
#include "het_chatgpt.h"  // <-- 唯一必须包含的头文件

static RK_BOOL enPa = RK_FALSE;
RK_S32 query_ao_flow_graph_stat(AUDIO_DEV aoDevId, AO_CHN aoChn) {
    RK_S32 ret = 0;
    AO_CHN_STATE_S pstStat;
    memset(&pstStat, 0, sizeof(AO_CHN_STATE_S));
    ret = RK_MPI_AO_QueryChnStat(aoDevId, aoChn, &pstStat);
    if (ret == RK_SUCCESS) {
        HET_LOGD("query ao flow status:\r\n");
        HET_LOGD("total number of channel buffer : %d\r\n", pstStat.u32ChnTotalNum);
        HET_LOGD("free number of channel buffer : %d\r\n", pstStat.u32ChnFreeNum);
        HET_LOGD("busy number of channel buffer : %d\r\n", pstStat.u32ChnBusyNum);
    }
	return ret;
}

static AUDIO_SOUND_MODE_E HET_AO_Find_Sound_Mode(RK_S32 ch) {
    AUDIO_SOUND_MODE_E channel = AUDIO_SOUND_MODE_BUTT;
    HET_LOGE("HET_AO_Find_Sound_Mode:  ch= %d\r\n", ch);
    switch (ch) {
      case 1:
        channel = AUDIO_SOUND_MODE_MONO;
        break;
      case 2:
        channel = AUDIO_SOUND_MODE_STEREO;
        break;
      default:
        HET_LOGE("channel = %d not support\r\n", ch);
        return AUDIO_SOUND_MODE_BUTT;
    }

    return channel;
}

static AUDIO_BIT_WIDTH_E find_bit_width(RK_S32 bit) {
    AUDIO_BIT_WIDTH_E bitWidth = AUDIO_BIT_WIDTH_BUTT;
    switch (bit) {
      case 8:
        bitWidth = AUDIO_BIT_WIDTH_8;
        break;
      case 16:
        bitWidth = AUDIO_BIT_WIDTH_16;
        break;
      case 24:
        bitWidth = AUDIO_BIT_WIDTH_24;
        break;
      default:
        HET_LOGE("bitwidth(%d) not support\r\n", bit);
        return AUDIO_BIT_WIDTH_BUTT;
    }

    return bitWidth;
}
/*
sprintf((char *)aoAttr.u8CardName, "%s", "hw:0,0");

	aoAttr.soundCard.channels = 2;               // 2
	aoAttr.soundCard.sampleRate = s32SampleRate; // s32SampleRate;       16000
	aoAttr.soundCard.bitWidth = AUDIO_BIT_WIDTH_16;

	aoAttr.enBitwidth = AUDIO_BIT_WIDTH_16;                   // AUDIO_BIT_WIDTH_16
	aoAttr.enSamplerate = (AUDIO_SAMPLE_RATE_E)s32SampleRate; // 16000

	aoAttr.enSoundmode = AUDIO_SOUND_MODE_MONO;
	aoAttr.u32PtNumPerFrm = u32FrameCnt; // 1024
	//以下参数没有特殊需要，无需修改
	aoAttr.u32FrmNum = 4;
	aoAttr.u32EXFlag = 0;
	aoAttr.u32ChnCnt = 2;

	RK_MPI_AO_SetPubAttr(aoDevId, &aoAttr);
	RK_MPI_AO_Enable(aoDevId);
	pstParams.enLoopbackMode = AUDIO_LOOPBACK_NONE;
*/

/**
 * @brief 创建音频通道 
 * @param ctx 音频通道参数
 * @return 成功返回0，失败返回-1
 */
static RK_S32 HET_AO_CreateChn(HET_AO_CTX_S *ctx) {
	RK_S32 s32Ret = RK_FAILURE;

    s32Ret = RK_MPI_AO_SetPubAttr(ctx->s32DevId, &ctx->stAoAttr);
	if (s32Ret != RK_SUCCESS) {
		HET_LOGE("SetPubAttr failed with %#x!\r\n", s32Ret);
        return s32Ret;
    }
	
    // 先不考虑多通道
    s32Ret = RK_MPI_AO_Enable(ctx->s32DevId);
    if (s32Ret != RK_SUCCESS) {
		HET_LOGE("Enable failed with %#x!\r\n", s32Ret);
        return s32Ret;
    }

	AO_CHN_PARAM_S pstParams;

    memset(&pstParams, 0, sizeof(AO_CHN_PARAM_S));
	pstParams.enLoopbackMode = AUDIO_LOOPBACK_NONE;
    s32Ret = RK_MPI_AO_SetChnParams(ctx->s32DevId, ctx->s32ChnId, &pstParams);
    if (s32Ret != RK_SUCCESS) {
        HET_LOGE("set channel params fail, aiChn = %d\r\n", ctx->s32ChnId);
        return RK_FAILURE;
    }
#if 0
    if (params->s32VqeEnable) {
        AO_VQE_CONFIG_S vqe_config;
        memset(&vqe_config, 0, sizeof(AO_VQE_CONFIG_S));
        if (params->pVqeCfgPath != RK_NULL) {
            vqe_config.enCfgMode = AIO_VQE_CONFIG_LOAD_FILE;
            memcpy(vqe_config.aCfgFile, params->pVqeCfgPath, strlen(params->pVqeCfgPath));
        }

        HET_LOGD("enCfgMode = %d", vqe_config.enCfgMode);
        ret = RK_MPI_AO_SetVqeAttr(params->s32DevId, params->s32ChnIndex, &vqe_config);
        if (ret) {
            HET_LOGE("ao set vqe attr fail, aoChn = %d, reason = %X", params->s32ChnIndex, ret);
            return ret;
        }

        ret = RK_MPI_AO_EnableVqe(params->s32DevId, params->s32ChnIndex);
        if (ret) {
            HET_LOGE("ao enable vqe fail, aoChn = %d, reason = %X", params->s32ChnIndex, ret);
            return ret;
        }
    }
#endif

	
    if (ctx->s32SetTrackMode) {
		// if (channel == 1)
		// 	RK_MPI_AO_SetTrackMode(aoDevId, AUDIO_TRACK_OUT_STEREO);
		// else
		// 	RK_MPI_AO_SetTrackMode(aoDevId, AUDIO_TRACK_NORMAL);
        HET_LOGD("test info : set track mode = %d", ctx->s32SetTrackMode);
        s32Ret = RK_MPI_AO_SetTrackMode(ctx->s32DevId, (AUDIO_TRACK_MODE_E)ctx->s32SetTrackMode);
		if (s32Ret != RK_SUCCESS) {
			HET_LOGE("EnableReSmp failed with %#x , aoChn = %d!\r\n", s32Ret, ctx->s32ChnId);
			return s32Ret;
		}
    }
    s32Ret =  RK_MPI_AO_EnableChn(ctx->s32DevId, ctx->s32ChnId);
    if (s32Ret != RK_SUCCESS) {
		HET_LOGE("EnableChn failed with %#x!\r\n", s32Ret);
        return s32Ret;
    }
    // set sample rate of input data
	s32Ret = RK_MPI_AO_EnableReSmp(ctx->s32DevId, ctx->s32ChnId,
								(AUDIO_SAMPLE_RATE_E)ctx->s32ChnSampleRate);
	if (s32Ret != RK_SUCCESS) {
			HET_LOGE("EnableReSmp failed with %#x , aoChn = %d!\r\n", s32Ret, ctx->s32ChnId);
		return s32Ret;
	}
    if(ctx->s32SetVolume != -1)
        RK_MPI_AO_SetVolume(ctx->s32DevId, ctx->s32SetVolume);
		
    HET_LOGD("Set volume curve type: %d", ctx->s32SetVolumeCurve);
    if ((ctx->s32SetVolumeCurve == AUDIO_CURVE_LOGARITHM) ||
        (ctx->s32SetVolumeCurve == AUDIO_CURVE_CUSTOMIZE)) {
        AUDIO_VOLUME_CURVE_S volumeCurve;

        volumeCurve.enCurveType = (AUDIO_VOLUME_CURVE_E)ctx->s32SetVolumeCurve;
        volumeCurve.s32Resolution = 101;
        volumeCurve.fMinDB = -51.0f;
        volumeCurve.fMaxDB = 0.0f;
        volumeCurve.pCurveTable = RK_NULL; // here none means using default logarithm curve by default.
        if (volumeCurve.enCurveType == AUDIO_CURVE_CUSTOMIZE) {
            volumeCurve.pCurveTable = (RK_U32 *)calloc(volumeCurve.s32Resolution, sizeof(RK_U32));
            RK_ASSERT(volumeCurve.pCurveTable != RK_NULL);
            // TODO: fill your customize table of volume curve folllowing to:
            // volumeCurve.pCurveTable[0, resolution-1]
        }
        RK_MPI_AO_SetVolumeCurve(ctx->s32DevId, &volumeCurve);
    }

	return RK_SUCCESS;
}

/**
 * @brief 销毁音频通道 
 * @param ctx 音频通道参数
 * @return 成功返回0，失败返回-1
 */
RK_S32 HET_AO_DestroyChn(HET_AO_CTX_S *ctx) {
	RK_S32 s32Ret = RK_FAILURE;

	s32Ret = RK_MPI_AO_DisableReSmp(ctx->s32DevId, ctx->s32ChnId);
    if (s32Ret != 0) {
        HET_LOGE("disable resample fail, reason = %d\r\n", s32Ret);
        return RK_FAILURE;
    }

	s32Ret |= RK_MPI_AO_DisableChn(ctx->s32DevId, ctx->s32ChnId);
	if (s32Ret != RK_SUCCESS) {
		HET_LOGE("DisableChn failed with %#x!\r\n", s32Ret);
		return RK_FAILURE;
	}

	s32Ret = RK_MPI_AO_Disable(ctx->s32DevId);
	if (s32Ret != RK_SUCCESS) {
		HET_LOGE("Disable failed with %#x!\r\n", s32Ret);
		return RK_FAILURE;
	}
	if(ctx->AudioData){
		free(ctx->AudioData);
		ctx->AudioData = NULL;
	}

	return RK_SUCCESS;
}
static void mpi_ao_attr_show_options(const AIO_ATTR_S *ctx,int aiDevId) {
    HET_LOGD("AO_ATTR:%d\r\n", aiDevId);
    HET_LOGD("u8CardName      : %s\r\n", ctx->u8CardName?(char *)ctx->u8CardName:"NULL");
    HET_LOGD("soundCard.channels      : %d\r\n", ctx->soundCard.channels);
    HET_LOGD("soundCard.sampleRate            : %d\r\n", ctx->soundCard.sampleRate);
    HET_LOGD("soundCard.bitWidth        : %d\r\n", ctx->soundCard.bitWidth==AUDIO_BIT_WIDTH_16?16:ctx->soundCard.bitWidth==AUDIO_BIT_WIDTH_24?24:8);
    HET_LOGD("u32ChnCnt          : %d\r\n", ctx->u32ChnCnt);
    HET_LOGD("enBitwidth       : %d\r\n", ctx->enBitwidth==AUDIO_BIT_WIDTH_16?16:ctx->enBitwidth==AUDIO_BIT_WIDTH_24?24:8);
    HET_LOGD("enSamplerate      : %d\r\n", ctx->enSamplerate);
    HET_LOGD("enSoundmode    : %s\r\n", ctx->enSoundmode==AUDIO_SOUND_MODE_MONO?"AUDIO_SOUND_MODE_MONO":ctx->enSoundmode==AUDIO_SOUND_MODE_STEREO?"AUDIO_SOUND_MODE_STEREO":"OTHER");
    HET_LOGD("u32FrmNum        : %d\r\n", ctx->u32FrmNum);
    HET_LOGD("u32PtNumPerFrm             : %d\r\n", ctx->u32PtNumPerFrm);
    HET_LOGD("u32EXFlag          : %d\r\n", ctx->u32EXFlag);
}
RK_BOOL get_sound_out_stat(){
	return enPa;
}
RK_S32 sendToAO(HET_AO_CTX_S *ctx,int sendSize){
	RK_S32 result;
    // set default value for struct
    RK_U64 timeStamp = 0;

    AUDIO_FRAME_S frame;
    RK_S32 s32MilliSec = -1;
	frame.u32Len = sendSize;
	frame.u64TimeStamp = timeStamp++;
	frame.enBitWidth = ctx->stAoAttr.enBitwidth;
	frame.enSoundMode = ctx->stAoAttr.enSoundmode;
	frame.bBypassMbBlk = RK_FALSE;
	MB_EXT_CONFIG_S extConfig;
	memset(&extConfig, 0, sizeof(extConfig));
	extConfig.pOpaque = ctx->AudioData + ctx->AudioOffset;
	extConfig.pu8VirAddr = ctx->AudioData + ctx->AudioOffset;
	extConfig.u64Size = sendSize;
	
	result = RK_MPI_SYS_CreateMB(&(frame.pMbBlk), &extConfig);
	if(result != 0){
		HET_LOGE("CreateMB fail:%X\r\n", result);
		return -1;
	}
__RETRY:
	result = RK_MPI_AO_SendFrame(ctx->s32DevId, ctx->s32ChnId, &frame, s32MilliSec);
	if (result < 0) {
		HET_LOGE("send frame fail, result = %X, TimeStamp = %lld, s32MilliSec = %d\r\n",
			result, frame.u64TimeStamp, s32MilliSec);
		goto __RETRY;
	}
	result = RK_MPI_MB_ReleaseMB(frame.pMbBlk);
}

RK_S32 het_ao_init(HET_AO_CTX_S *ctx){
	RK_S32 result;
	//ctx->s32PeriodCount = ctx->s32ChnCnt * ctx->s32BitWidth;
	HET_LOGD("AO #Device: %s\r\n", ctx->cardName?ctx->cardName:"NULL");
	HET_LOGD("AO #SampleRate: %d\r\n", ctx->s32ChnSampleRate);
	HET_LOGD("AO #Channel Count: %d\r\n", ctx->s32ChnCnt);
	HET_LOGD("AO #Loop Count: %d\r\n", ctx->s32loopCount);
	HET_LOGD("AO #Output Path: %s\r\n", ctx->dstFilePath?ctx->dstFilePath:"NULL");
	HET_LOGD("AO #read Path: %s\r\n", ctx->readDataFile?ctx->readDataFile:"NULL");
	ctx->AudioSize = ctx->s32ChnSampleRate * ctx->s32PeriodCount;//1s
	ctx->AudioData = NULL;
	ctx->AudioOffset = 0;
	HET_LOGD("AO #AudioSize: %d\r\n", ctx->AudioSize);
	HET_LOGD("AO #PeriodCount: %d\r\n", ctx->s32PeriodCount);
	// Init AO[0]
	ctx->s32DevId = AO_DEV_ID;
	ctx->s32ChnId = AO_CHN_ID;
	ctx->stAoAttr.soundCard.channels = ctx->s32DeviceChannel;
	ctx->stAoAttr.soundCard.sampleRate = ctx->s32DeviceSampleRate;
	ctx->stAoAttr.soundCard.bitWidth = (AUDIO_BIT_WIDTH_E)ctx->s32BitWidth;
	ctx->stAoAttr.u32ChnCnt = ctx->s32ChnCnt;
	ctx->stAoAttr.enBitwidth = (AUDIO_BIT_WIDTH_E)ctx->s32BitWidth;
	ctx->stAoAttr.enSamplerate = (AUDIO_SAMPLE_RATE_E)ctx->s32ChnSampleRate;
	ctx->stAoAttr.enSoundmode = HET_AO_Find_Sound_Mode(ctx->s32ChnCnt);
	ctx->stAoAttr.u32FrmNum = ctx->s32PeriodCount;
	ctx->stAoAttr.u32PtNumPerFrm = ctx->s32PeriodSize;
	if(!ctx->s32DataReadEnable)
		ctx->stAoAttr.u32EXFlag = 0;
	else
		ctx->stAoAttr.u32EXFlag = 1;
	if (ctx->cardName) {
		strcpy((char *)ctx->stAoAttr.u8CardName, ctx->cardName);
	}
	mpi_ao_attr_show_options(&ctx->stAoAttr, ctx->s32DevId);
	result = HET_AO_CreateChn(ctx);
    if(result != 0){
		HET_LOGE("AO_CreateChn fail:%d\r\n", result);
		return result;
	}
	ctx->AudioData = (RK_CHAR *)malloc(ctx->AudioSize);
	if(!ctx->AudioData){
		HET_LOGE("AudioData malloc fail:%d\r\n");
		return -3;
	}
	return result;
}
RK_S32 het_ao_deinit(HET_AO_CTX_S *ctx){
	RK_MPI_AO_WaitEos(ctx->s32DevId, ctx->s32ChnId, -1);
	HET_LOGD("DestroyChn!\r\n");
	if(ctx->AudioData){
		free(ctx->AudioData);
		ctx->AudioData = NULL;
	}
    HET_AO_DestroyChn(ctx);
	return 0;
}

/**
 * @brief 设置音量
 * @param params 音频参数
 * @return 成功返回0，失败返回-1
 */
RK_S32 HET_AO_apply_Volume(int volume) {
    RK_S32 result;

    g_ctx.ao.s32SetVolume = volume;
    RK_MPI_AO_SetVolume(g_ctx.ao.s32DevId, g_ctx.ao.s32SetVolume);
    return RK_SUCCESS;
}
/**
 * @brief 设置静量
 * @param params 音频参数
 * @return 成功返回0，失败返回-1
 */
RK_S32 HET_AO_apply_Mute(int s32SetMute) {
    RK_S32 result;

    g_ctx.ao.s32SetMute = s32SetMute;
	if(enPa ){
		if(g_ctx.ao.s32SetMute || g_ctx.ao.s32SetVolume == 0) {
			result = RK_MPI_AMIX_SetControl(g_ctx.ao.s32DevId, (char*)"DAC Control Manually", (char*)"Off");
			if (result != RK_SUCCESS) {
				RK_LOGE("ao set DAC Control Manually fail, reason = %x", result);
			}
			enPa = RK_FALSE;
			HET_LOGD("apply pa on:%d\r\n", enPa);
		}
	}
    return RK_SUCCESS;
}
#define USE_FILE 1
/******************************************************************************
 * function : ao thread
 ******************************************************************************/

/**
 * @brief 音频处理线程
 * @param pArgs 音频参数
 * @return 成功返回0，失败返回-1
 */
void* HET_AO_Play_Stream_Thread(void * pArgs) {
	HET_AO_CTX_S *ctx = (HET_AO_CTX_S *)(pArgs);

    RK_S32 s32MilliSec = -1;
    MB_POOL_CONFIG_S pool_config;
	HET_LOGD("HET_AO_Play_Stream_Thread enter\r\n");
    int readSize = 0, sendSize;
    RK_S32 result = 0;
    RK_U32 sendTotal = 0;
	RK_BOOL hasPlay = RK_FALSE;
	het_ao_init(ctx);
	HET_LOGD("ao_run %d\r\n",ao_run);
	while (global_run) {
		if(!ao_run){
			//HET_LOGD("ao waiting\r\n");
            //printf("%");
			if(enPa){
				HET_LOGD("output audio stop\r\n");
    			//RK_MPI_AO_WaitEos(ctx->s32DevId, ctx->s32ChnId, 10);
				result = RK_MPI_AMIX_SetControl(ctx->s32DevId, "DAC Control Manually", "Off");
				if (result != RK_SUCCESS) {
					RK_LOGE("ao set DAC Control Manually fail, reason = %x", result);
				}
				enPa = RK_FALSE;
				HET_LOGI("on run pa off:%d\r\n", enPa);
				usleep(100000);
			}
			usleep(10000);
			continue;
		}
		// 从缓冲区读取数据
		if( readSize== 0)
			readSize = rb_pop(&audioPlayBuf,(char *)ctx->AudioData,  ctx->AudioSize);
		
		//HET_LOGD("r:%d\r\n", readSize);
		if(readSize > 0){
			//HET_LOGD("w p:%d\r\n", readSize);
			if(!enPa){
				if(!g_ctx.ao.s32SetMute && g_ctx.ao.s32SetVolume > 0) {
					AUDIO_FADE_S fade;
					RK_MPI_AO_SetMute(ctx->s32DevId,1,&fade);
					usleep(10000);
					result = RK_MPI_AMIX_SetControl(ctx->s32DevId, "DAC Control Manually", "On");
					if (result != RK_SUCCESS) {
						RK_LOGE("ao set DAC Control Manually fail, reason = %x", result);
					}
					enPa = RK_TRUE;
					RK_MPI_AO_SetMute(ctx->s32DevId,0,&fade);
					HET_LOGI("pa on:%d\r\n", enPa);
				}else{
					HET_LOGD("pa can't on m %d v:%d\r\n", g_ctx.ao.s32SetMute, g_ctx.ao.s32SetVolume);
				}
			}
			ctx->AudioOffset = 0;
			// 按照帧大小发送数据
			while((int)readSize > 0){
				sendSize = readSize > ctx->s32PeriodSize?ctx->s32PeriodSize:readSize;
				//HET_LOGD("b r:%d s:%d o:%d\r\n", readSize, sendSize, ctx->AudioOffset);
				if(sendToAO(ctx,sendSize) == 0)
					hasPlay = RK_TRUE;
				// 更新发送数据大小
				sendTotal += sendSize;
				readSize -= sendSize;
				ctx->AudioOffset += sendSize;
				//HET_LOGD("a r:%d s:%d o:%d\r\n", readSize, sendSize, ctx->AudioOffset);
			}
		} else{
            //printf("#");
			if(enPa){
				HET_LOGD("output audio finish\r\n");
				if(hasPlay){
					//HET_LOGD("_+++\r\n");
					//usleep(250000);
					RK_MPI_AO_WaitEos(ctx->s32DevId, ctx->s32ChnId, 300);
					hasPlay = RK_FALSE;
					//HET_LOGD("_---\r\n");
				}
				result = RK_MPI_AMIX_SetControl(ctx->s32DevId, (char*)"DAC Control Manually", (char*)"Off");
				if (result != RK_SUCCESS) {
					RK_LOGE("ao set DAC Control Manually fail, reason = %x", result);
				}
				usleep(100000);
				enPa = RK_FALSE;
				HET_LOGI("pa off:%d\r\n", enPa);
			}else{
				usleep(100000);
			}
		}
    }

__EXIT:
	// 退出前要等待音频输出完毕
	HET_LOGE("total %zu!\r\n",sendTotal);
	het_ao_deinit(ctx);
	HET_LOGE("exit!\r\n");
    return RK_NULL;
}